<?php
/**
 * Coffee Framework

 * @category   CF
 * @package    CF_db
 * @author     그네 <Jung Sik, Park> <ccooffeee at hotmail dot com>
 * @copyright  Copyright (c) 2009 Jung Sik, Park <ccooffeee at hotmail dot com>
 * @license    doc/LICENSE    Based New BSD License
 * @version    $Id: db.php,v 0.1.3 2010/08/09 ccooffeee Exp $

 * LICENSE

 * 본 프로그램은 New BSD License 를 기본으로 하고 있지만 약간 다른 제약조건을 가지고 있습니다. 
 * 함께 제공된 license file 인  doc/LICENSE 를 꼭 확인하시길 바랍니다.

 * This Source is subject to the New BSD License with SOME CONSTRAINT that is boudled
 * with this package in the file doc/LICENSE 
 */


require_once __DIR__.'/exception.php';
require_once __DIR__.'/interface.php';


abstract class CF_db_abstract implements CF_db_interface
{
// {{{ properties
	// config: driver, name, user, password, server,
	//			encoding, port
	protected $config = null;
	protected $dao = null;
	protected $stmt = null;
	protected $transaction = false;
// }}}

// {{{ constructor
	public function __construct($config) {
		if($config instanceof CF_config_iterator)
			$this->config = $config->to_array();

		if(is_array($config)) 
			$this->config = $config;


		$this->_checkOption();

		$this->connect();
	}
// }}}

// {{{ destructor
	public function __destruct () {
		$this->rollback();
		$this->free();
		$this->close();
	}
// }}}


// {{{ void begin ()
	public function begin () {
		$this->connect();

		if($this->transaction === true) return;

		$this->dao->beginTransaction();
		$this->transaction = true;
	}
// }}}
// {{{ void commit ()
	public function commit() {
		if($this->dao === null) return;
		if($this->transaction !== true) return;

		$this->dao->commit();
		$this->transaction = false;
	}
// }}}
// {{{ void rollback ([string savepoint])
	public function rollback($savepoint = null) {
		if($this->dao === null) return;
		if($this->transaction !== true) return;

		$this->dao->rollback();
		$this->transaction = false;
	}
// }}}

// {{{ CF_db_interface query (string sql, array param)
	public function query ($query, array $param = array()) {
		$this->connect();

		try {
			if($this->stmt instanceof PDOStatement)
				$this->stmt->closeCursor();

			$this->stmt = $this->dao->prepare($query);

			if(!$this->stmt) {
				$err = $this->dao->errorInfo();
				throw new CF_db_exception($err[2]);
			}

			if(count($param) > 0)
				$this->stmt->execute($this->_bind($param));
			else $this->stmt->execute();
		} catch (PDOException $e) {
			throw new CF_db_exception ($e->getMessage(), $e->getCode(), $e);
		}

		return $this;
	}
// }}}
// {{{ mixed fetch ([string mode]) 
	public function fetch($mode = null) {
		$mode = $mode == 'array' ? PDO::FETCH_ASSOC : PDO::FETCH_OBJ;
		try { return $this->stmt->fetch($mode); }
		catch (PDOException $e) {
			throw new CF_db_exception ($e->getMessage(), $e->getCode(), $e);
		}
	}
// }}}
// {{{ mixed fetchAll ([string mode])
	public function fetchAll($mode = null) {
		$mode = $mode == 'array' ? PDO::FETCH_ASSOC : PDO::FETCH_OBJ;
		try { return $this->stmt->fetchAll($mode); }
		catch (PDOException $e) {
			throw new CF_db_exception ($e->getMessage(), $e->getCode(), $e);
		}
	}
// }}}
// {{{ string field ([integer col_index])
	public function field($index = 0) {
		if($this->stmt === null) return null;

		$index = (int)$index;
		return $this->stmt->fetchColumn($index);
	}
// }}}

// {{{ string insertId ([string seq_name])
	public function insertId($name = null) {
		if($this->dao === null) return null;

		return $this->dao->lastInsertId($name);
	}
// }}}
// {{{ int rowCount ()
	public function rowCount() {
		if($this->stmt === null) return 0;

		return $this->stmt->rowCount();
	} 
// }}}

// {{{ void free ()
	public function free() {
		$this->stmt = null;
	}
// }}}

// {{{ boolean isConnect ()
	public function isConnect() {
		return $this->dao instanceof PDO;
	}
// }}}
// {{{ void close ()
	public function close() {
		$this->dao = null;
	}
// }}}


// {{{ protected methods
	// {{{ void _checkOption ()
	protected function _checkOption() {
		if(!isset($this->config['driver']) || !$this->config['driver'])
			throw new CF_db_exception ("Configure must have a 'driver' key that names the database driver name");
		if(!isset($this->config['name']) || !$this->config['name'])
			throw new CF_db_exception ("Configure must have a 'name' key that names the database name");
		if(!isset($this->config['user']) || !$this->config['user'])
			throw new CF_db_exception ("Configure must have a 'user' key that names the database login name");
		if(!isset($this->config['password']))
			throw new CF_db_exception ("Configure must have a 'password' key that names the database password");
		if(!isset($this->config['server']) || !$this->config['server'])
			throw new CF_db_exception ("Configure must have a 'server' key that names the database host");
	}
	// }}}
	// {{{ void exec (string sql)
	protected function exec($query)
	{
		$this->connect();

		try {
			$aff = $this->dao->exec($query);
			if($aff === false) {
				$err = $this->dao->errorInfo();
				throw new CF_db_exception ($err[2]);
			}

		} catch (PDOException $e) {
			throw new CF_db_exception ($e->getMessage(), $e->getCode(), $e);
		}
	}
	// }}}
	// {{{ array _bind (array)
	protected function _bind (array $bind = array()) {
		array_walk($bind, function(&$val, &$key) {
			if(!is_array($val) && !is_int($val)) {
				//if($this->_isQuoted())
				if(isset($_SERVER['HTTP_HOST']) && get_magic_quotes_gpc())
					$val = stripslashes($val);
			}

			if(!is_int($key) && !preg_match('/^:/', $key)) 
				$key = ':'.$key;
		});

		return $bind;
	}
	// }}}
	// {{{ boolean _isQuoted ()
	protected function _isQuoted() {
		if(isset($_SERVER['HTTP_HOST']) && get_magic_quotes_gpc())
			return true;

		return false;
	}
	// }}}
	// {{{ void connect ()
	protected function connect() {
		if($this->dao !== null) return;
		if($this->config === null) return;

		
		$dsn = $this->configToDsn();

		if(!extension_loaded('pdo'))
			throw new CF_db_exception ('PDO extension is required');

		if(!in_array($this->config['driver'], PDO::getAvailableDrivers()))
			throw new CF_db_exception($this->config['driver'].' driver: Not Support');

		try {
			$this->dao = new PDO ($dsn, $this->config['user'], $this->config['password']);
			$this->init();
		} Catch (PDOException $e) {
			throw new CF_db_exception ($e->getMessage(), $e->getCode(), $e);
		}
	}
	// }}}
	// {{{ string configToDsn ()
	protected function configToDsn() {
		if($this->config === null) return null;

		if(!isset($this->config['driver']) || !$this->config['driver'])
			return null;

		$dsn = $this->config['driver'].':';
		if(!isset($this->config['server']) || !$this->config['server'])
			return null;

		$dsn .= 'host='.$this->config['server'].';';
		if(isset($this->config['port']) && $this->config['port'])
			$dsn .= 'port='.$this->config['port'].';';
		$dsn .= 'dbname='.$this->config['name'];

		return $dsn;
	}
	// }}}
	// {{{ void init ()
	protected function init() {
		$this->dao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	}
	// }}}
// }}}


	// {{{ __call ()
	public function __call($method, array $params = array()) {
		throw new CF_db_exception('Call to undefined method: '.get_class($this).'::'.$method.'()');
	}
	// }}}
}

// vim: ts=4 sw=4 fdm=marker
?>
